
`include "common_header.verilog"

//  *************************************************************************
//  File : enc8b10b_xgxs.v
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited. 
//  Copyright (c) 2002-2003-2004 Morethanip
//  An der Steinernen Brueke 1, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Sebastien Marcellier
//  fbalay@morethanip.com
//  *************************************************************************
//  Decription : Encoder (Transmission code 8b/10b)
//  Version    : $Id: enc8b10b_xgxs.v,v 1.1 2011/03/29 10:37:06 mr Exp $
//  *************************************************************************

module enc8b10b_xgxs (

   din,
   kin,
   disp,
   rd_in,
   ce,
   dout,
   clk,
`ifdef USE_CLK_ENA
   clk_ena,
`endif    
   sw_reset,
   rst);
   
input   [7:0] din;      //  Parallel byte of incoming data
input   kin;            //  Special caracter request  	
output  disp;           //  Current Disparity
input   rd_in;          //  Disparity
input   ce;             //  Asserted when input data are stable
output  [9:0] dout;     //  Parallel output data        
input   clk;            //  Main Clock 
`ifdef USE_CLK_ENA
input   clk_ena;        // Enable clk
`endif 
input   sw_reset;       //  SW Asynchronous Reset                          
input   rst;            //  Asynchronour reset
wire    disp; 
reg     [9:0] dout;
wire    [5:0] code_5b6b_index ;
wire    [3:0] code_3b4b_index ;

// -----------------------------------------------------------------------------
//  Internal signals
// -----------------------------------------------------------------------------
//  Output of the 5b/6b block output after the control disparity
reg    [5:0] data_out_6b; 
//  Output of the 3b/4b block output after the control disparity
reg    [3:0] data_out_4b; 
//  Output of the 3b/4b block output after the reverse due to
//  the exception in the 3B/4B block
wire    [3:0] data_out_4b_reverse; 
//   Ouput in case of a special character request
wire    [9:0] data_out_sc; 
//  Running disparity at the 6 bit block ouput
reg    rd_out_6b; 
//  Running disparity at the 4 bit block ouput
reg    rd_out_4b; 
//  Running disparity at the special character ouput
wire    rd_out_sc; 
//  Exception A7 replace P7
wire    except; 

// ---------------------------------------
//  DATA ENCODING & DATA DISPARITY CONTROL
// ---------------------------------------
//  5b/6b Encoding 

assign code_5b6b_index={rd_in, din[4:0]} ;

always@(code_5b6b_index)
begin

        case(code_5b6b_index)
        
                6'h0: data_out_6b=6'b 111001; 
                6'h1: data_out_6b=6'b 101110; 
                6'h2: data_out_6b=6'b 101101; 
                6'h3: data_out_6b=6'b 100011; 
                6'h4: data_out_6b=6'b 101011; 
                6'h5: data_out_6b=6'b 100101; 
                6'h6: data_out_6b=6'b 100110; 
                6'h7: data_out_6b=6'b 000111; 
                6'h8: data_out_6b=6'b 100111; 
                6'h9: data_out_6b=6'b 101001; 
                6'hA: data_out_6b=6'b 101010; 
                6'hB: data_out_6b=6'b 001011; 
                6'hC: data_out_6b=6'b 101100; 
                6'hD: data_out_6b=6'b 001101; 
                6'hE: data_out_6b=6'b 001110; 
                6'hF: data_out_6b=6'b 111010; 
                6'h10: data_out_6b=6'b 110110;
                6'h11: data_out_6b=6'b 110001;
                6'h12: data_out_6b=6'b 110010;
                6'h13: data_out_6b=6'b 010011;
                6'h14: data_out_6b=6'b 110100;
                6'h15: data_out_6b=6'b 010101;
                6'h16: data_out_6b=6'b 010110;
                6'h17: data_out_6b=6'b 010111;
                6'h18: data_out_6b=6'b 110011;
                6'h19: data_out_6b=6'b 011001;
                6'h1A: data_out_6b=6'b 011010;
                6'h1B: data_out_6b=6'b 011011;
                6'h1C: data_out_6b=6'b 011100;
                6'h1D: data_out_6b=6'b 011101;
                6'h1E: data_out_6b=6'b 011110;
                6'h1F: data_out_6b=6'b 110101;
                6'h20: data_out_6b=6'b 000110;
                6'h21: data_out_6b=6'b 010001;
                6'h22: data_out_6b=6'b 010010;
                6'h23: data_out_6b=6'b 100011;
                6'h24: data_out_6b=6'b 010100;
                6'h25: data_out_6b=6'b 100101;
                6'h26: data_out_6b=6'b 100110;
                6'h27: data_out_6b=6'b 111000;
                6'h28: data_out_6b=6'b 011000;
                6'h29: data_out_6b=6'b 101001;
                6'h2A: data_out_6b=6'b 101010;
                6'h2B: data_out_6b=6'b 001011;
                6'h2C: data_out_6b=6'b 101100;
                6'h2D: data_out_6b=6'b 001101;
                6'h2E: data_out_6b=6'b 001110;
                6'h2F: data_out_6b=6'b 000101;
                6'h30: data_out_6b=6'b 001001;
                6'h31: data_out_6b=6'b 110001;
                6'h32: data_out_6b=6'b 110010;
                6'h33: data_out_6b=6'b 010011;
                6'h34: data_out_6b=6'b 110100;
                6'h35: data_out_6b=6'b 010101;
                6'h36: data_out_6b=6'b 010110;
                6'h37: data_out_6b=6'b 101000;
                6'h38: data_out_6b=6'b 001100;
                6'h39: data_out_6b=6'b 011001;
                6'h3A: data_out_6b=6'b 011010;
                6'h3B: data_out_6b=6'b 100100;
                6'h3C: data_out_6b=6'b 011100;
                6'h3D: data_out_6b=6'b 100010;
                6'h3E: data_out_6b=6'b 100001;
                6'h3F: data_out_6b=6'b 001010;
                
        endcase
        
        case(code_5b6b_index)
        
                6'h0: rd_out_6b=1'b 1; 
                6'h1: rd_out_6b=1'b 1; 
                6'h2: rd_out_6b=1'b 1; 
                6'h3: rd_out_6b=1'b 0; 
                6'h4: rd_out_6b=1'b 1; 
                6'h5: rd_out_6b=1'b 0; 
                6'h6: rd_out_6b=1'b 0; 
                6'h7: rd_out_6b=1'b 0; 
                6'h8: rd_out_6b=1'b 1; 
                6'h9: rd_out_6b=1'b 0; 
                6'hA: rd_out_6b=1'b 0; 
                6'hB: rd_out_6b=1'b 0; 
                6'hC: rd_out_6b=1'b 0; 
                6'hD: rd_out_6b=1'b 0; 
                6'hE: rd_out_6b=1'b 0; 
                6'hF: rd_out_6b=1'b 1; 
                6'h10: rd_out_6b=1'b 1;
                6'h11: rd_out_6b=1'b 0;
                6'h12: rd_out_6b=1'b 0;
                6'h13: rd_out_6b=1'b 0;
                6'h14: rd_out_6b=1'b 0;
                6'h15: rd_out_6b=1'b 0;
                6'h16: rd_out_6b=1'b 0;
                6'h17: rd_out_6b=1'b 1;
                6'h18: rd_out_6b=1'b 1;
                6'h19: rd_out_6b=1'b 0;
                6'h1A: rd_out_6b=1'b 0;
                6'h1B: rd_out_6b=1'b 1;
                6'h1C: rd_out_6b=1'b 0;
                6'h1D: rd_out_6b=1'b 1;
                6'h1E: rd_out_6b=1'b 1;
                6'h1F: rd_out_6b=1'b 1;
                6'h20: rd_out_6b=1'b 0;
                6'h21: rd_out_6b=1'b 0;
                6'h22: rd_out_6b=1'b 0;
                6'h23: rd_out_6b=1'b 1;
                6'h24: rd_out_6b=1'b 0;
                6'h25: rd_out_6b=1'b 1;
                6'h26: rd_out_6b=1'b 1;
                6'h27: rd_out_6b=1'b 1;
                6'h28: rd_out_6b=1'b 0;
                6'h29: rd_out_6b=1'b 1;
                6'h2A: rd_out_6b=1'b 1;
                6'h2B: rd_out_6b=1'b 1;
                6'h2C: rd_out_6b=1'b 1;
                6'h2D: rd_out_6b=1'b 1;
                6'h2E: rd_out_6b=1'b 1;
                6'h2F: rd_out_6b=1'b 0;
                6'h30: rd_out_6b=1'b 0;
                6'h31: rd_out_6b=1'b 1;
                6'h32: rd_out_6b=1'b 1;
                6'h33: rd_out_6b=1'b 1;
                6'h34: rd_out_6b=1'b 1;
                6'h35: rd_out_6b=1'b 1;
                6'h36: rd_out_6b=1'b 1;
                6'h37: rd_out_6b=1'b 0;
                6'h38: rd_out_6b=1'b 0;
                6'h39: rd_out_6b=1'b 1;
                6'h3A: rd_out_6b=1'b 1;
                6'h3B: rd_out_6b=1'b 0;
                6'h3C: rd_out_6b=1'b 1;
                6'h3D: rd_out_6b=1'b 0;
                6'h3E: rd_out_6b=1'b 0;
                6'h3F: rd_out_6b=1'b 0;
                
        endcase
        
end

assign code_3b4b_index={rd_out_6b, din[7:5]} ;

always@(code_3b4b_index)
begin

        case(code_3b4b_index)
        
                4'h0: data_out_4b=4'b 1101;
                4'h1: data_out_4b=4'b 1001;
                4'h2: data_out_4b=4'b 1010;
                4'h3: data_out_4b=4'b 0011;
                4'h4: data_out_4b=4'b 1011;
                4'h5: data_out_4b=4'b 0101;
                4'h6: data_out_4b=4'b 0110;
                4'h7: data_out_4b=4'b 0111;
                4'h8: data_out_4b=4'b 0010;
                4'h9: data_out_4b=4'b 1001;
                4'hA: data_out_4b=4'b 1010;
                4'hB: data_out_4b=4'b 1100;
                4'hC: data_out_4b=4'b 0100;
                4'hD: data_out_4b=4'b 0101;
                4'hE: data_out_4b=4'b 0110;
                4'hF: data_out_4b=4'b 1000;
                
        endcase
        
        case(code_3b4b_index)
        
                4'h0: rd_out_4b=1'b 1;
                4'h1: rd_out_4b=1'b 0;
                4'h2: rd_out_4b=1'b 0;
                4'h3: rd_out_4b=1'b 0;
                4'h4: rd_out_4b=1'b 1;
                4'h5: rd_out_4b=1'b 0;
                4'h6: rd_out_4b=1'b 0;
                4'h7: rd_out_4b=1'b 1;
                4'h8: rd_out_4b=1'b 0;
                4'h9: rd_out_4b=1'b 1;
                4'hA: rd_out_4b=1'b 1;
                4'hB: rd_out_4b=1'b 1;
                4'hC: rd_out_4b=1'b 0;
                4'hD: rd_out_4b=1'b 1;
                4'hE: rd_out_4b=1'b 1;
                4'hF: rd_out_4b=1'b 0;
        
        endcase
        
end

assign except = (rd_in == 1'b 1 & din[4:0] == 5'b 01011 | 
	rd_in == 1'b 1 & din[4:0] == 5'b 01101 | 
	rd_in == 1'b 1 & din[4:0] == 5'b 01110 | 
	rd_in == 1'b 0 & din[4:0] == 5'b 10001 | 
	rd_in == 1'b 0 & din[4:0] == 5'b 10010 | 
	rd_in == 1'b 0 & din[4:0] == 5'b 10100) & 
	din[7:5] == 3'b 111 ? 1'b 1 : 
	1'b 0; 
assign data_out_sc[0] = din[0] ^ rd_in; 
assign data_out_sc[1] = din[1] ^ rd_in; 
assign data_out_sc[2] = din[2] ^ rd_in; 
assign data_out_sc[3] = din[3] ^ rd_in; 
assign data_out_sc[4] = din[4] ^ rd_in; 
assign data_out_sc[5] = !din[0] & !din[1] & din[2] & din[3] & din[4] ^ rd_in; 
assign data_out_sc[6] = din[5] & !(din[6] & !din[7]) ^ rd_in; 
assign data_out_sc[7] = !din[5] & !(!din[6] & din[7]) ^ rd_in; 
assign data_out_sc[8] = (din[7] & !(din[5] & din[6]) | din[5] & din[6] & !din[7]) ^ rd_in; 
assign data_out_sc[9] = !din[7] & !(!din[5] & !din[6]) ^ rd_in; 
// ------------------------------------
//  SPECIAL CHARACTER DISPARITY CONTROL
// ------------------------------------   
assign rd_out_sc = !din[0] & !din[1] & din[2] & din[3] & 
	din[4] & (din[5] ^ din[6] | din[5] & 
	din[6] & !din[7]) ^ rd_in; 
// -------------------------------------------------------
//  OUTPUT REGISTER & DATA/SPECIAL CHARACTERS MULTIPLEXING
// -------------------------------------------------------
always @(posedge clk or posedge rst)
   begin : p_output
   if (rst == 1'b 1)
      begin
      dout <= {10{1'b 0}};	
      end
   else
      begin
      
         `ifdef USE_CLK_ENA
            if(clk_ena == 1'b 1)
            begin
         `endif        
      
              if (sw_reset == 1'b 1)
                 begin
                 dout <= {10{1'b 0}};	
                 end
              else if (ce == 1'b 1 )
                 begin
                 if (kin == 1'b 0)
                    begin
                    dout <= {data_out_4b_reverse, data_out_6b};	
                    end
                 else
                    begin
                    dout <= data_out_sc;	
                    end
                 end
            
         `ifdef USE_CLK_ENA
            end
         `endif       
      
      end
   end

assign disp = kin == 1'b 0 ? rd_out_4b : rd_out_sc; 
assign data_out_4b_reverse[0] = except == 1'b 0 ? data_out_4b[0] : data_out_4b[3 - 0]; 
assign data_out_4b_reverse[1] = except == 1'b 0 ? data_out_4b[1] : data_out_4b[3 - 1]; 
assign data_out_4b_reverse[2] = except == 1'b 0 ? data_out_4b[2] : data_out_4b[3 - 2]; 
assign data_out_4b_reverse[3] = except == 1'b 0 ? data_out_4b[3] : data_out_4b[3 - 3];  

endmodule // module enc8b10b_xgxs

